import urllib
import urllib2
import cookielib
import json
import time
import os.path
import pickle

import threading
import Setting
from wx.lib.pubsub import setuparg1
from wx.lib.pubsub import pub

import DataManager

class SyncError(Exception):
    ERROR_LOGIN_FAIL = -1
    ERROR_LOGOUT_FAIL = -2
    ERROR_PUSH_FAIL = -3
    ERROR_PULL_FAIL = -4


    def __init__(self, value, string):
        self.value = value
        self.string = string
        print(value, string)

    def __str__(self):
        return repr((self.value, self.string))

class SyncManager(threading.Thread):
    #I still need to think this over
    main_url = 'https://daydayup-timemanager.rhcloud.com/'
    login_url = 'https://daydayup-timemanager.rhcloud.com/account/login'
    logout_url = 'https://daydayup-timemanager.rhcloud.com/account/logout'
    userdata_url = 'https://daydayup-timemanager.rhcloud.com/userdata/'
    pull_targets = ('wishlist/pull', 'collector/pull', 'todolist/pull',
                    'record/pull', 'primetype/pull', 'subtype/pull')
    push_targets = (('wishlist/push','wish'),
                    ('collector/push','collect'),
                    ('todolist/push','todo'))

    def __init__(self):

        self.pull_ret = []
        cj = cookielib.CookieJar()
        cookie = urllib2.HTTPCookieProcessor(cj)
        if os.path.exists('proxy.ini'):
            print('use proxy file')
            proxy = pickle.load(open('proxy.ini', 'rb'))
        else:
            proxy = urllib.getproxies()
            if not proxy == {}:
                print('use system proxy')

        proxy_handler = urllib2.ProxyHandler(proxy)
        self.opener = urllib2.build_opener(cookie, urllib2.HTTPHandler, proxy_handler)
        self.level = -1
        urllib2.install_opener(self.opener)

        threading.Thread.__init__(self)

    def run(self):
        try:
            self.sync()
        except:
            pass

    def sync(self):

        """
        API used by other module
        """
        print('sync start')
        #step-1:get st
        self.st = self.get_last_sync_time()
        #step0:setup connection
        h = self.setup()
        #step0.5 login
        self.level = 1
        self.login()
        print('login done')
        #step1:pull
        #all in one list, for they share the same structure
        self.level = 2
        self.pull()
        print('pull done')
        self.level = 3
        #step2:merge
        self.merge()
        print('merge done')
        self.level = 4
        #step3:push
        self.push()
        print('push done')
        self.level = 5
        self.logout()
        print('logout done')
        self.level = 6
        self.cleanup()
        self.set_last_sync_time(int(time.time()))
        self.real_cleanup()
        print('sync done')
        self.level = 0
        #step4:when all these are over, we need to quit, to make sure
        #that those marked as deleted are really deleted
        #those marked as not synced should be marked as synced
        return 0


    def setup(self):
        un = Setting.Setting.get('username')
        pw = Setting.Setting.get('password')
        #this dict is used to generate data
        self.base_dict = {}
        self.base_dict['username'] = un
        self.base_dict['password'] = pw
        self.base_dict['visit_type'] = 'pc'
        self.base_dict2 = {}
        self.base_dict2['username'] = un
        self.base_dict2['visit_type'] = 'pc'

    def login(self):
        req = urllib2.Request(self.login_url, urllib.urlencode(self.base_dict))
        try:
            resp = urllib2.urlopen(req, timeout=50)
        except:
            raise SyncError(SyncError.ERROR_LOGIN_FAIL, 'login error')
        data = json.loads(resp.read())
        if data['status'] != 0:
            print(data['status'])
            print(data['message'])
            raise SyncError((data['status'], data['message']))


    def logout(self):
        req = urllib2.Request(self.logout_url)
        try:
            resp = urllib2.urlopen(req, timeout=50)
        except:
            raise SyncError(SyncError.ERROR_LOGOUT_FAIL, 'logout error')
        data = json.loads(resp.read())
        if data['status'] != 0:
            print(data['status'])
            print(data['message'])
            raise SyncError((data['status'], data['message']))

    def pull(self):
        retl = []
        for i in self.pull_targets:
            url = self.userdata_url + i
            t = self.get_data(url)
            self.pull_ret.append(t)

    def get_data(self, url):
        data = dict(self.base_dict2)
        data['last_time'] = self.st
        req = urllib2.Request(url, urllib.urlencode(data))
        resp = urllib2.urlopen(req, timeout=50)
        a = resp.read()
        l = json.loads(a)
        if l['status'] == 20:
            l = l['data']
        elif l['status'] == 21 or l['status'] == 22:
            l = []
        else:
            raise SyncError(l['status'], '')
        return l

    def merge(self):
        #two tasks:
        #1. delete
        #2. add
        #it's very foolish of us to arrange the sequence of data in this
        #stupid way. Because I have to write 2 blocks of code
        lists = (DataManager.DataManager.wishlist,
                 DataManager.DataManager.collectlist,
                 DataManager.DataManager.todolist,
                 DataManager.DataManager.record)
        for j,i in enumerate(lists):
            self.merge_single_list(self.pull_ret[j], i)

    def merge_single_list(self, dict_list, model_list):
        for i in dict_list:
            model_list.merge(i)
        model_list.refresh()
            
        

    def push(self):
        from ModelBaseList import ListItem
        for i in self.push_targets:
            url = i[0]
            name = i[1]
            ret1 = DataManager.DataManager.db.querry("select * from %s where stat > 0"%(name))
            ret = []
            for i in ret1:
                ret.append(ListItem.get_diff(i))
            ret2 = DataManager.DataManager.db.querry("select ct, mt from %s where stat == -1"%(name))
            for i in ret2:
                tmp = {}
                tmp['ctime'] = i[0]
                tmp['mtime'] = i[1]
                tmp['stime'] = int(time.time())
                tmp['status'] = 1
                ret.append(tmp)
            self.do_push(self.userdata_url + url, ret)


    def do_push(self, url, data):
        data_to_send = dict(self.base_dict2)
        data_to_send['data'] = json.dumps(data)
        r = urllib.urlencode(data_to_send)
        req = urllib2.Request(url, r)
        resp = urllib2.urlopen(req, timeout=50)
        r = json.loads(resp.read())
        if r['status'] <= 20 and r['status'] != 0:
            raise SyncError(r['status'], r['message'])

    def cleanup(self):
        #since we do not modify record lists, there's no need to touch it
        for i in ('wish', 'collect', 'todo'):
            #1. delete deleted
            DataManager.DataManager.db.after_sync_cleanup(i)


    def set_last_sync_time(self, tm):
        DataManager.DataManager.db.add('history', '(' + str(tm) + ')')

    def get_last_sync_time(self):
        try:
            last = DataManager.DataManager.db.querry('select max(st) from history')
            return last[0][0]
        except:
            return 0

    def real_cleanup(self):
        if not Setting.Setting.get('save_password'):
            Setting.Setting.set('password', '')


class RegisterManager():
    def __init__(self):
        cj = cookielib.CookieJar()
        cookie = urllib2.HTTPCookieProcessor(cj)
        if os.path.exists('proxy.ini'):
            print('use proxy file')
            proxy = pickle.load(open('proxy.ini', 'rb'))
        else:
            proxy = urllib.getproxies()
            if not proxy == {}:
                print('use system proxy')

        proxy_handler = urllib2.ProxyHandler(proxy)

        self.opener = urllib2.build_opener(cookie, urllib2.HTTPHandler, proxy_handler)
    def do_register(self, un, pw):
        rurl = 'https://daydayup-timemanager.rhcloud.com/account/register'
        resp = self.opener.open(rurl, urllib.urlencode(
                {'username':un, 'password':pw}))
        d = json.loads(resp.read())
        return d['status']
        



if __name__ == '__main__':
    DataManager.DataManager.init()
    Setting.Setting.init()
    Setting.Setting.set('username', 'denglx')
    Setting.Setting.set('password', '123456')
    uut = SyncManager()
    ret = uut.sync()
    if ret == 0:
        print("PASS")
